﻿using ScFramework.Core;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;


public class SubPhysicsManager : SubmoduleBase ,ISubPhysicsManager
{
    Dictionary<BelongingSystem, ISubPhysics> subDic;
    public uint Create(BelongingSystem sys, ElementState state, Vector2 pos)
    {
        return subDic[sys].Create(state, pos);
    }

    public void Delete(BelongingSystem sys, uint id)
    {
        subDic[sys].Delete(id);
    }
    public List<CollisionArgs> GetCollisionArgs()
    {
        var ans = new List<CollisionArgs>();
        foreach(var x in subDic.Values)
        {
            ans.AddRange(x.GetCollideInfo());
        }
        return ans;
    }

    public BasicInfo GetInfo(BelongingSystem sys, uint id)
    {
        return subDic[sys].GetInfo(id);
    }

    public List<Tuple<BelongingSystem, uint>> GetOverlapBox(Vector2 pos, Vector2 siz, float angle)
    {
        List<Tuple<BelongingSystem, uint>> ans = new List<Tuple<BelongingSystem, uint>>();
        foreach(var x in subDic)
        {
            ans.AddRange(x.Value.GetOverlapBox(pos, siz, angle).ConvertAll(s=>new Tuple<BelongingSystem, uint>(x.Key,s)));
        }
        return ans;
    }

    public override void OnInit(object args)
    {
        base.OnInit(args);
        subDic = new Dictionary<BelongingSystem, ISubPhysics>();
        var lis = Gets<ISubPhysics>();
        foreach(var x in lis)
        {
            Debug.Assert(subDic.ContainsKey(x.GetSystemType) == false);
            subDic[x.GetSystemType] = x;
            x.SetPosChecker(GameMode.Instance.PosChecker);
        }
        GetSystemModule<MessageManager>().Get<MapEvent>().RegisterHandler(MapEvent.MapSave, Save);

    }

    public void SetInfo(BelongingSystem sys, uint id, BasicInfo info)
    {
        subDic[sys].SetInfo(id, info);
    }
    public EventArgs Save(object sender, EventArgs e)
    {
        Dictionary<BelongingSystem, string> saveDic = new Dictionary<BelongingSystem, string>();
        saveDic.Add(BelongingSystem.Ground, subDic[BelongingSystem.Ground].GetAllData() as string);
        saveDic.Add(BelongingSystem.Fluid,subDic[BelongingSystem.Fluid].GetAllData() as string);

        SceneData sceneData = new SceneData { sysDatas = saveDic };

        var datas = JsonConvert.SerializeObject(sceneData);
        string path = MapEditManager.pathSave;
        System.IO.File.Create(path).Dispose();
        System.IO.StreamWriter sw = new System.IO.StreamWriter(path);
        sw.Write(datas);
        sw.Close();
        return null;
    }

    public void SetAllData(BelongingSystem sys, object data)
    {
        if (subDic.ContainsKey(sys) == false)
        {
            Debug.LogError($"Not found {sys}");
            return;
        }
        subDic[sys].SetAllData(data);
    }


    public bool AddWorldForceAtLocalPotision(BelongingSystem sys, uint id, Vector2 localPosition, Vector2 worldForce)
    {
        throw new NotImplementedException();
    }
}
public interface ISubPhysicsManager
{
    BasicInfo GetInfo(BelongingSystem sys, uint id);
    void SetInfo(BelongingSystem sys, uint id, BasicInfo info);
    uint Create(BelongingSystem sys, ElementState state, Vector2 pos);

    void Delete(BelongingSystem sys, uint id);

    List<Tuple<BelongingSystem, uint>> GetOverlapBox(Vector2 pos, Vector2 siz, float angle);

    List<CollisionArgs> GetCollisionArgs();
    bool AddWorldForceAtLocalPotision(BelongingSystem sys, uint id, Vector2 localPosition, Vector2 worldForce);
    void SetAllData(BelongingSystem sys, object data);
}
public enum SubPhysicsEvent
{
    CheckInstance,
    GetCollideInfo,

}


public abstract class SubPhysicsModule : LogicModuleBase<MessageManager>, ISubPhysics
{
    /// <summary>
    /// 物体位置
    /// 用于检测当摄像机位置指定时该物体位置的物体能否被实例化
    /// </summary>
    protected Func<Vector2, bool> posChecker;
    public void SetPosChecker(Func<Vector2, bool> pc)
    {
        posChecker = pc;
        
    }

    public abstract uint Create(ElementState state, Vector2 pos);
  //  public abstract void Create(uint id, Vector2 pos);
    public abstract void Delete(uint id);
    public abstract object GetAllData();
    public abstract List<CollisionArgs> GetCollideInfo();
    public abstract BasicInfo GetInfo(uint id);
    public abstract void SetAllData(object datas);
    public abstract void SetInfo(uint id, BasicInfo info);
    public abstract void CheckInstance();

    public abstract List<uint> GetOverlapBox(Vector2 pos, Vector2 siz, float angle);

    public abstract bool AddWorldForceAtLocalPotision(uint id, Vector2 localPosition, Vector2 worldForce);

    public abstract BelongingSystem GetSystemType { get; }
}

public interface ISubPhysics
{
    /// <summary>
    /// 获取系统类型
    /// </summary>
    /// <returns></returns>
    BelongingSystem GetSystemType { get; }

    BasicInfo GetInfo(uint id);
    void SetInfo(uint id, BasicInfo info);

    /// <summary>
    /// 检测实例是否需要被实例化
    /// </summary>
    /// <param name="cameraPos"></param>
    void CheckInstance();
    /// <summary>
    /// 获取当前系统的所有数据，用于存档或联机
    /// </summary>
    /// <returns></returns>
    object GetAllData();

    List<uint> GetOverlapBox(Vector2 pos, Vector2 siz, float angle);
    /// <summary>
    /// datas might be null
    /// 
    /// </summary>
    /// <param name="datas"></param>
    void SetAllData(object datas);

    uint Create(ElementState state,Vector2 pos);

    //void Create(uint id, Vector2 pos);

    void Delete(uint id);

    List<CollisionArgs> GetCollideInfo();

    void SetPosChecker(Func<Vector2, bool> pc);


    bool AddWorldForceAtLocalPotision(uint id, Vector2 localPosition, Vector2 worldForce);

}

public interface ISubPhysicsCollider
{
    Tuple<uint, BelongingSystem, ElementState> GetObjectInfo();
    List<CollideInfo> GetCollideInfos(Collision2D obj);
}

public class CollideInfo
{
    public Tuple<uint, BelongingSystem, ElementState> Identity;
    public Vector2 CollidePositionInWorld;
    public Vector2 Force;
    public CollideInfo(Tuple<uint,BelongingSystem,ElementState>id,Vector2 pos,Vector2 f)
    {
        Identity = id;
        CollidePositionInWorld = pos;
        Force = f;
    }
}